package com.vcredit.creditcat.service.product;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.vcredit.bird.service.mobile.MobileProcessService;
import com.vcredit.bird.service.zmxy.ZmxyProcessService;
import com.vcredit.bird.vo.mobile.MobileCallHistory;
import com.vcredit.bird.vo.mobile.MobileVarible;
import com.vcredit.bird.vo.zmxy.ZmxyDetailExtendInfo;
import com.vcredit.bird.vo.zmxy.ZmxyScoreDetail;
import com.vcredit.creditcat.Exception.ProductApplyException;
import com.vcredit.creditcat.dto.product.h5.CheckOrderResultDto;
import com.vcredit.creditcat.enumtype.AuthItemEnum;
import com.vcredit.creditcat.enumtype.CommonEducationConvertEnum;
import com.vcredit.creditcat.enumtype.CommonMarriageConvertEnum;
import com.vcredit.creditcat.enumtype.ProductApiEnum;
import com.vcredit.creditcat.enumtype.auth.SupplementItemEnum;
import com.vcredit.creditcat.model.AddressList;
import com.vcredit.creditcat.model.AuthPersonalAddress;
import com.vcredit.creditcat.model.Cust;
import com.vcredit.creditcat.model.CustProductApply;
import com.vcredit.creditcat.model.CustSupplementItem;
import com.vcredit.creditcat.model.ProductApiUrl;
import com.vcredit.creditcat.model.base.AbstractItem;
import com.vcredit.creditcat.service.ProductApiUrlService;
import com.vcredit.creditcat.service.product.h5.AfterCreditService;
import com.vcredit.creditcat.service.product.h5.CommonApiRequestService;
import com.vcredit.creditcat.util.ConcurrentDateUtil;
import com.vcredit.creditcat.util.Utility;
import com.vcredit.creditcat.vo.ProductApplyResultVo;
import com.vcredit.creditcat.vo.auth.AuthIdentityExt;
import com.vcredit.creditcat.vo.auth.AuthMobileExt;
import com.vcredit.creditcat.vo.auth.AuthPersonalInfoExt;
import com.vcredit.creditcat.vo.auth.AuthSecreditExt;
import com.vcredit.creditcat.vo.auth.RelativeListExt;
import com.vcredit.creditcat.vo.product.CommonProductCreditResultVo;
import com.vcredit.creditcat.vo.product.h5.CallTimeComparator;
import com.vcredit.creditcat.vo.product.h5.CommonResultVo;
import com.vcredit.creditcat.vo.product.h5.SubmitPhoneBaseInfo;
import com.vcredit.creditcat.vo.product.h5.SubmitPhoneCallInfo;
import com.vcredit.creditcat.vo.product.h5.SubmitPhoneParam;
import com.vcredit.creditcat.vo.product.h5.ZhiMaScoreDetail;
import com.vcredit.creditcat.vo.product.h5.ZhiMaScoreDetailExtendInfo;
import com.vcredit.creditcat.vo.product.h5.ZhiMaScoreInfo;
import com.vcredit.framework.annotation.Log;
import com.vcredit.framework.util.JacksonUtil;

@Service
public class CommonProductApplyNewService implements IProductApplyNewService{
	
	private static final Logger LOG = LoggerFactory.getLogger(CommonProductApplyNewService.class);

	public static final String BASEINFO_URL_ENDS = "new_base_info/commit";
	
	@Autowired
	private ProductApiUrlService productApiUrlService;
	@Autowired
	private CommonApiRequestService commonApiRequestService;
	@Autowired
	private MobileProcessService mobileProcessService;
	@Autowired
	private ZmxyProcessService zmxyProcessService;
	@Autowired
	private AfterCreditService afterCreditService;
	
	@Value("${resource.soft.url}")
	private String imagUrl;
	
	/**
	 * 基本信息、刷脸高实、手机、芝麻分、紧急联系人
	 */
	@Log
	@Override
	public ProductApplyResultVo apply(
			Map<Integer, AbstractItem> custAuthInfoMap,
			Map<Long, CustSupplementItem> custSupplementItemMap,
			Map<String, Object> otherParams) {
		
		try {
			Long productId = (Long)otherParams.get("productId");
			// 校验该产品的授信接口是否有配置，如果没有则抛异常
			String creditUrl = this.getProductApiUrl(productId, ProductApiEnum.CREDIT.getType());
			if(null == creditUrl) {
				return new ProductApplyResultVo("产品无授信API");
			}
			
			Cust cust = (Cust)otherParams.get("cust");
			// 取出认证项数据
			CustSupplementItem baseInfoSupplement = custSupplementItemMap.get(SupplementItemEnum.Common_BASE_INFO.getItemId());
			// 基本信息
			AuthPersonalInfoExt personalInfo = JacksonUtil.Json2Obj(baseInfoSupplement.getDataEntity(), new TypeReference<AuthPersonalInfoExt>(){});	
			// 活体认证
			AuthIdentityExt identity = (AuthIdentityExt)custAuthInfoMap.get(AuthItemEnum.VERIFY_FACE_PAIR.getCode());
			// 手机
			AuthMobileExt authMobile = (AuthMobileExt)custAuthInfoMap.get(AuthItemEnum.MOBILE.getCode());
			// 芝麻分
			AuthSecreditExt secreditExt = (AuthSecreditExt)custAuthInfoMap.get(AuthItemEnum.SESAME_CREDIT.getCode());
			// 紧急联系人
			RelativeListExt relativeListVo = (RelativeListExt)custAuthInfoMap.get(AuthItemEnum.CONTACTS.getCode());
			
			// 判断可交单
			CheckOrderResultDto checkUserResult = afterCreditService.checkUser(productId, cust);
			if(!checkUserResult.getCanLoanFlag()) { // 可交单未通过，申请失败
				CustProductApply custProductApply = new CustProductApply();
				custProductApply.setAuditResult(0);
				custProductApply.setIsApply(false);
				custProductApply.setRejectMsg(checkUserResult.getFailTips());
				return new ProductApplyResultVo(custProductApply);
			}
			
			// 提交基本信息
			this.submitBaseInfo(productId,cust,personalInfo,identity,secreditExt,relativeListVo,authMobile);
			
			// 提交通讯录
			this.submitTongxunlu(productId,cust,relativeListVo);
			
			// 提交运营商数据 
			this.submitPhone(authMobile, cust.getCustId(), productId);
			
			// 授信
			CustProductApply custProductApply = this.credit(productId, cust);
			return new ProductApplyResultVo(custProductApply);
		} catch (ProductApplyException e1) {
			LOG.error("------------CommonProductApplyNewService.apply 异常!!",e1);
			return new ProductApplyResultVo(e1.getErrMsg());
		} catch (Exception e2) {
			LOG.error("------------CommonProductApplyNewService.apply 异常!!",e2);
			return new ProductApplyResultVo("系统异常，请稍后再试");
		} 
	}
	
	/**
	 * 提交运营商数据
	 * @author zhaoqi01
	 * @param authMobile
	 * @param identity
	 * @throws Exception 
	 */
	private void submitPhone(AuthMobileExt authMobile,Long custId, Long productId) throws Exception {
		// 查询基础信息
		MobileVarible mobileVaible = mobileProcessService.mobileVaible(authMobile.getMobileId());
		// 封装base
		SubmitPhoneBaseInfo base = new SubmitPhoneBaseInfo(mobileVaible.getMobile(), mobileVaible.getCity(), 
				mobileVaible.getRegdate(), mobileVaible.getBusName(), 
				mobileVaible.getIdentityCard(), ConcurrentDateUtil.formatDateTime(authMobile.getUpdateTime()));
		
		// 封装call
		Map<String, Set<SubmitPhoneCallInfo>> call = this.packageCall(authMobile.getMobileId());
		
		// 流量使用情况 TODO 目前蜂鸟返回的都是-9999999
		Map<String,String> gprs = new HashMap<String,String>();
		gprs.put("total_flow", "");
		
		SubmitPhoneParam submitParam = new SubmitPhoneParam(AfterCreditService.CUSTID_PREFIX + custId, 
				base, call, gprs);
		
		String paramJson = JacksonUtil.Obj2Json(submitParam);		
		String url=this.getProductApiUrl(productId, ProductApiEnum.SUBMIT_MOBILE_INFO.getType());
		LOG.info("------------CommonProductApplyNewService.submitPhone入参：" + paramJson+"#"+url);
		String resultJson = commonApiRequestService.wrapRequest(url, paramJson, true);
		LOG.info("------------CommonProductApplyNewService.submitPhone出参：" + resultJson);
		CommonResultVo<CommonProductCreditResultVo> commonResult = JacksonUtil.Json2Obj(resultJson, new TypeReference<CommonResultVo<CommonProductCreditResultVo>>(){});
		
		if(!commonResult.isSuccess()) {
			throw new ProductApplyException("提交运营商数据失败");
		}
	}
	
	private Map<String,Set<SubmitPhoneCallInfo>> packageCall(String mobileId) throws Exception {
		// 查询童话记录
		List<MobileCallHistory> calls = mobileProcessService.queryCalls(mobileId);
		// 封装call
		Map<String,Set<SubmitPhoneCallInfo>> call = new HashMap<String,Set<SubmitPhoneCallInfo>>();
		
		Map<String,Set<SubmitPhoneCallInfo>> tempCall = new HashMap<String,Set<SubmitPhoneCallInfo>>();
		for(MobileCallHistory mobileCall : calls) {
			SubmitPhoneCallInfo callInfo = new SubmitPhoneCallInfo(mobileCall.getStartTime(), 
					mobileCall.getCallPlace(), mobileCall.getOtherCallPhone(), 
					mobileCall.getInitType(), mobileCall.getUseTime(), 
					mobileCall.getCallType(), mobileCall.getSubTotal() == null ? 0L : (long)(mobileCall.getSubTotal() * 100));
		
			Date startDate = ConcurrentDateUtil.strToDate(mobileCall.getStartTime());
			String formatYMDate = ConcurrentDateUtil.formatYMDate(startDate);
			
			Set<SubmitPhoneCallInfo> set = tempCall.get(formatYMDate);
			if(null == set) {
				set = new TreeSet<SubmitPhoneCallInfo>(new CallTimeComparator());
				set.add(callInfo);
				tempCall.put(formatYMDate, set);
			} else {
				set.add(callInfo);
			}
		}
		
		// 取最近2个月的通话记录
		Set<SubmitPhoneCallInfo> tmpSet = new TreeSet<SubmitPhoneCallInfo>(new CallTimeComparator());
		for (String dateStr : tempCall.keySet()) { // 排序
			SubmitPhoneCallInfo submitPhoneCallInfo = new SubmitPhoneCallInfo();
			submitPhoneCallInfo.setCalltime(dateStr);
			tmpSet.add(submitPhoneCallInfo);
		}
		int i = 0;
		for(SubmitPhoneCallInfo info : tmpSet) {
			if(i == 2) {
				break;
			}
			call.put(info.getCalltime(), tempCall.get(info.getCalltime()));
			i++;
		}
		
		return call;
	}
	
	/**
	 * 提交授信
	 * @author zhaoqi01
	 * @param productId
	 * @param cust
	 * @return
	 * @throws Exception 
	 */
	private CustProductApply credit(Long productId, Cust cust) throws Exception {
		Map<String,String> paramMap = new HashMap<String,String>();
		paramMap.put("user_id", AfterCreditService.CUSTID_PREFIX + cust.getCustId());
		String paramJson = JacksonUtil.Obj2Json(paramMap);
		String url=this.getProductApiUrl(productId, ProductApiEnum.CREDIT.getType());
		LOG.info("------------CommonProductApplyNewService.credit入参：" + paramJson+"#"+url);
		String resultJson = commonApiRequestService.wrapRequest(url, paramJson, false);
		LOG.info("------------CommonProductApplyNewService.credit出参：" + resultJson);
		CommonResultVo<CommonProductCreditResultVo> commonResult = JacksonUtil.Json2Obj(resultJson, new TypeReference<CommonResultVo<CommonProductCreditResultVo>>(){});
		
		CustProductApply result = new CustProductApply();
		if(!commonResult.isSuccess()) { // 授信失败
			result.setAuditResult(0);
			result.setRejectMsg(commonResult.getMsg());
			result.setIsApply(true);
			result.setCreditApplyTime(ConcurrentDateUtil.formatDateTime(DateUtils.addDays(new Date(), 30)));
			return result;
		}
		CommonProductCreditResultVo data = commonResult.getData();
		 if("1".equals(data.getStatus() + "")) { // 授信提交被接收，等待授信结果
			 result.setAuditResult(2); // 审批中
		 } else { // 授信成功
			 result.setAuditResult(1);
			 result.setCreditAmt(data.getMax_amount().intValue() * 100);
			 result.setServiceRate(data.getCutting_rate());
			 result.setCreditExpiretime(data.getAmount_validity() + " 00:00:00");
			 result.setIsApply(false);
			 result.setCreditApplyTime("");
			 result.setMaxAmount(data.getMax_amount().intValue() * 100);
			 result.setMinAmount(data.getMin_amount().intValue() * 100);
			 result.setRangeAmount(data.getRange_amount() * 100);
			 result.setLoanTerm(data.getLoan_term());
			 result.setLoanTermType(data.getLoan_term_type());
			 result.setLoanRate(data.getLoan_rate());
			 result.setCuttingAmount(data.getCutting_amount());
		 }
		
		return result;
	}

	/**
	 * 提交通讯录数据
	 * @author zhaoqi01
	 * @param productId
	 * @param cust
	 * @param personalInfo
	 * @throws Exception 
	 */
	private void submitTongxunlu(Long productId, Cust cust,
			RelativeListExt relativeListExt) throws Exception {
		List<String> tongxunluList = new ArrayList<String>();
		List<AddressList> addressList = relativeListExt.getAddressList();
		for (AddressList address : addressList) {
			tongxunluList.add(address.getName() + "_" + address.getMobile());
		}
		
		Map<String,String> paramMap = new HashMap<String,String>();
		paramMap.put("user_id", AfterCreditService.CUSTID_PREFIX + cust.getCustId());
		paramMap.put("phonelist", JacksonUtil.Obj2Json(tongxunluList));
		String paramJson = JacksonUtil.Obj2Json(paramMap);
		String url=this.getProductApiUrl(productId, ProductApiEnum.SUBMIT_TONGXUNLU.getType());
		LOG.info("------------CommonProductApplyNewService.submitTongxunlu入参：" + paramJson+"#"+url);	
		String resultJson = commonApiRequestService.wrapRequest(url, paramJson, true);
		LOG.info("------------CommonProductApplyNewService.submitTongxunlu出参：" + resultJson);
		CommonResultVo<Object> commonResult = JacksonUtil.Json2Obj(resultJson, new TypeReference<CommonResultVo<Object>>(){});
		
		if(!commonResult.isSuccess()) {
			throw new ProductApplyException("提交通讯录失败");
		}
	}

	/**
	 * 提交基本信息
	 * @author zhaoqi01
	 * @param productId
	 * @param cust
	 * @param personalInfo
	 * @param identity
	 * @param secreditExt
	 * @return
	 * @throws Exception 
	 */
	private void submitBaseInfo(Long productId, Cust cust,
			AuthPersonalInfoExt personalInfo, AuthIdentityExt identity,
			AuthSecreditExt secreditExt, RelativeListExt relativeListVo, 
			AuthMobileExt authMobile) throws Exception {
		Boolean newBaseInfo = false; // 是否为新的基本信息接口，新基本信息请求参数将zhima_score改为credit_score
		// 判断新老基本信息接口
		String baseInfoRequestUrl = this.getProductApiUrl(productId, ProductApiEnum.SUBMIT_BASEINFO.getType()).trim();
		if(baseInfoRequestUrl.contains(BASEINFO_URL_ENDS)) {
			// 新基本信息接口
			newBaseInfo = true;
		}
		
		AuthPersonalAddress personalLiveAddr = null; // 居住地址相关信息
		AuthPersonalAddress personalCompanyAddr = null; // 公司地址相关信息
		List<AuthPersonalAddress> personalAddrList = personalInfo.getPersonalAddrList();
		for (AuthPersonalAddress authPersonalAddress : personalAddrList) {
			if(authPersonalAddress.getAddressType() == 0) { // 公司
				personalCompanyAddr = authPersonalAddress;
			} else if(authPersonalAddress.getAddressType() == 2) { // 居住地
				personalLiveAddr = authPersonalAddress;
			}
		}
		
		Map<String,Object> paramMap = new HashMap<String,Object>(); 
		if(newBaseInfo) {// 新
			// 维信分
			paramMap.put("credit_score", this.calculateCreditScore(secreditExt.getZmxyScore(),identity));
		} else { // 旧
			List<ZhiMaScoreDetail> zhiMaScoreDetailList = new ArrayList<ZhiMaScoreDetail>();
			// 查询芝麻分行业关注名单 TODO
			List<ZmxyScoreDetail> zmfDetailList = zmxyProcessService.queryZmfDetail(identity.getCitizenId(), identity.getName());
			for (ZmxyScoreDetail zmxyScoreDetail : zmfDetailList) {
				List<ZhiMaScoreDetailExtendInfo> extendList = new ArrayList<ZhiMaScoreDetailExtendInfo>();
				for (ZmxyDetailExtendInfo detailExtend : zmxyScoreDetail.getExtendInfo()) {
					extendList.add(new ZhiMaScoreDetailExtendInfo(detailExtend.getDescription(), 
							detailExtend.getKey(), detailExtend.getValue()));
				}
				
				ZhiMaScoreDetail detail = new ZhiMaScoreDetail(zmxyScoreDetail.getBizCode(), 
						zmxyScoreDetail.getCode(), extendList, zmxyScoreDetail.getLevel(), 
						zmxyScoreDetail.getRefreshTime(), zmxyScoreDetail.getSettlement(),
						zmxyScoreDetail.getType());
				
				zhiMaScoreDetailList.add(detail);
			}
			
			ZhiMaScoreInfo zhiMaScoreInfo = new ZhiMaScoreInfo(secreditExt.getZmxyScore(),
					Utility.isNullOrEmpty(zmfDetailList) ? false : true,
							zhiMaScoreDetailList);
			
			paramMap.put("zhima_score", zhiMaScoreInfo); // 芝麻分，待行业关注名单
		}
		
		paramMap.put("user_id", AfterCreditService.CUSTID_PREFIX + cust.getCustId());
		paramMap.put("user_name", identity.getName());
		paramMap.put("user_idcard", identity.getCitizenId());
		paramMap.put("user_mobile", authMobile.getMobile());
		paramMap.put("educations", CommonEducationConvertEnum.getTcodeByScode(personalInfo.getEducationKey()));// 学历
		paramMap.put("marrital",CommonMarriageConvertEnum.getTcodeByScode(personalInfo.getMarriageKey())); // 婚姻状况
		paramMap.put("province", personalLiveAddr.getProvince()); // 居住省份
		paramMap.put("city", personalLiveAddr.getCity()); // 居住城市
		paramMap.put("county", personalLiveAddr.getZone()); // 居住城市区县
		paramMap.put("addr_detail", personalLiveAddr.getAddress()); // 详细居住地址
		paramMap.put("company", personalCompanyAddr.getAddressName()); // 公司名称
		paramMap.put("company_province", personalCompanyAddr.getProvince()); // 公司所在省
		paramMap.put("company_city", personalCompanyAddr.getCity()); // 公司所在市
		paramMap.put("company_county", personalCompanyAddr.getZone()); // 公司所在区县
		paramMap.put("company_addr_detail", personalCompanyAddr.getAddress()); // 公司详细地址
		paramMap.put("emergency_contact1_person_name", relativeListVo.getRelativeList().get(0).getRelationName()); // 紧急联系人1名字
		paramMap.put("emergency_contact1_person_phone", relativeListVo.getRelativeList().get(0).getRelationMobile()); // 紧急联系人1电话
		paramMap.put("emergency_contact1_person_relation", relativeListVo.getRelativeList().get(0).getRelationType()); // 紧急联系人1关系
		paramMap.put("emergency_contact2_person_name", relativeListVo.getRelativeList().get(1).getRelationName()); // 紧急联系人2名字
		paramMap.put("emergency_contact2_person_phone", relativeListVo.getRelativeList().get(1).getRelationMobile()); // 紧急联系人2电话
		paramMap.put("emergency_contact2_person_relation", relativeListVo.getRelativeList().get(1).getRelationType()); // 紧急联系人2关系
		paramMap.put("id_positive", imagUrl + "/" + identity.getIdFront()); // 身份证正面 URL
		paramMap.put("id_negative", imagUrl + "/" + identity.getIdBack()); // 身份证反面URL
		paramMap.put("ocr_img", JacksonUtil.Obj2Json(new String[]{imagUrl + "/" + identity.getIdFace()})); // 身份证活体URL
		
		String paramJson = JacksonUtil.Obj2Json(paramMap);
		LOG.info("------------CommonProductApplyNewService.submitBaseInfo入参：" + paramJson+"#"+baseInfoRequestUrl);
		String resultJson = commonApiRequestService.wrapRequest(baseInfoRequestUrl, paramJson, false);
		LOG.info("------------CommonProductApplyNewService.submitBaseInfo出参：" + resultJson);
		CommonResultVo<Object> commonResult = JacksonUtil.Json2Obj(resultJson, new TypeReference<CommonResultVo<Object>>(){});
		
		if(!commonResult.isSuccess()) {
			throw new ProductApplyException("提交基本信息失败");
		}
		
	}

	/**
	 * 计算维信分
	 * @author zhaoqi01
	 * @param zmxyScore
	 * @param identity
	 * @return
	 * @throws ParseException 
	 */
	private int calculateCreditScore(String zmxyScore,
			AuthIdentityExt identity) throws ParseException {
		// 先判断年龄大于55，如果大于55，维信分为0
		DateFormat df = new SimpleDateFormat("yyyy.MM.dd");
		int age = Utility.getAge(df.parse(identity.getBirthday()));
		if(age > 55) {
			return 0;
		}
		
		int zmf = Integer.parseInt(zmxyScore);
		// 芝麻分小于500，维信分为0
		if(zmf < 500) {
			return 0;
		}
		
		// 芝麻分等于500,维信分为1
		if(zmf == 500) {
			return 1;
		}
		
		return 1 + (zmf - 500) / 10; // 大于500多余的分数，10分作1分
	}
	
	/**
	 * 判断可交单
	 * @author zhaoqi01
	 * @param identity
	 * @param authMobile
	 * @return
	 * @throws Exception 
	 */
//	private CheckOrderResultDto checkUser(Long productId, AuthMobileExt authMobile) throws Exception {
//		String mobile = authMobile.getMobile();
//		String mobileEnd = mobile.substring(mobile.length() - 3);
//		
//		Map<String,String> paramMap = new HashMap<String,String>();
//		paramMap.put("user_mobile", mobileEnd);
//		paramMap.put("user_mobile_md5", MD5Util.md5(mobile));
//		
//		String paramJson = JacksonUtil.Obj2Json(paramMap);
//		LOG.info("------------CommonProductApplyNewService.checkUser入参：" + paramJson);
//		String resultJson = commonApiRequestService.wrapRequest(this.getProductApiUrl(productId, ProductApiEnum.CHECK_USER.getType()), paramJson, false);
//		LOG.info("------------CommonProductApplyNewService.checkUser出参：" + resultJson);
//		CommonResultVo<Map<String, String>> commonResult = JacksonUtil.Json2Obj(resultJson, new TypeReference<CommonResultVo<Map<String,String>>>(){});
//		if(commonResult.isSuccess()) {
//			if("1".equals(commonResult.getData().get("result"))) {
//				return new CheckOrderResultDto(true, null);
//			} else {
//				return new CheckOrderResultDto(false, commonResult.getMsg());
//			}
//		} else { // 请求失败，抛异常
//			throw new ProductApplyException("准入请求失败");
//		}
//	}

	public String getProductApiUrl(Long productId, Integer type) {
		Map<Long, Map<Integer, ProductApiUrl>> findAllForMap = productApiUrlService.findAllForMap();
		Map<Integer, ProductApiUrl> map = findAllForMap.get(productId.longValue());
		if(null == map) {
			return null;
		}
		
		ProductApiUrl productApiUrl = map.get(type.intValue());
		if(null == productApiUrl) {
			return null;
		}
		return productApiUrl.getApiUrl();
	}
}
